package br.edu.infnet.model;

import java.io.Serializable;

import javax.persistence.*;

import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;

import br.edu.infnet.dto.ClienteDTO;
import br.edu.infnet.dto.ContaDTO;
import br.edu.infnet.dto.DataAniversarioDTO;
import br.edu.infnet.dto.MovimentoDTO;
import br.edu.infnet.exception.BankException;
import br.edu.infnet.infraestrutura.AuthCodeGenerator;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;


/**
 * The persistent class for the conta database table.
 * 
 */
@Entity
@NamedQuery(name="Conta.findAll", query="SELECT c FROM Conta c")
public class Conta implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@Column(name="PK_CONTA")
	private int pkConta;

	private String codigo;

	@Temporal(TemporalType.DATE)
	@Column(name="DT_CRIACAO")
	private Date dtCriacao;

	@Column(name="ESTADO_CONTA")
	private int estadoConta;

	@Column(name="FK_AGENCIA")
	private int fkAgencia;

	private BigDecimal limite;

	@Column(name="RESPNSAVEL_ABERTURA")
	private String respnsavelAbertura;

	@Column(name="RESPONSAVEL_APROVACAO")
	private String responsavelAprovacao;

	private BigDecimal saldo;

	@Column(name="TIPO_CONTA")
	private int tipoConta;

	//bi-directional many-to-one association to Cliente
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="FK_CLIENTE")
	private Cliente cliente;

	//bi-directional many-to-one association to DataAniversario
	@OneToMany(mappedBy="conta")
	private List<DataAniversario> dataAniversarios;

	//bi-directional many-to-one association to Movimento
	@OneToMany(mappedBy="conta")
	private List<Movimento> movimentos;

	public Conta() {
		cliente = new Cliente();
		dataAniversarios = new ArrayList<DataAniversario>();
		movimentos = new ArrayList<Movimento>();
		
	}

	public int getPkConta() {
		return this.pkConta;
	}

	public void setPkConta(int pkConta) {
		this.pkConta = pkConta;
	}

	public String getCodigo() {
		return this.codigo;
	}

	public void setCodigo(String codigo) {
		this.codigo = codigo;
	}

	public Date getDtCriacao() {
		return this.dtCriacao;
	}

	public void setDtCriacao(Date dtCriacao) {
		this.dtCriacao = dtCriacao;
	}

	public int getEstadoConta() {
		return this.estadoConta;
	}

	public void setEstadoConta(int estadoConta) {
		this.estadoConta = estadoConta;
	}

	public int getFkAgencia() {
		return this.fkAgencia;
	}

	public void setFkAgencia(int fkAgencia) {
		this.fkAgencia = fkAgencia;
	}

	public BigDecimal getLimite() {
		return this.limite;
	}

	public void setLimite(BigDecimal limite) {
		this.limite = limite;
	}

	public String getRespnsavelAbertura() {
		return this.respnsavelAbertura;
	}

	public void setRespnsavelAbertura(String respnsavelAbertura) {
		this.respnsavelAbertura = respnsavelAbertura;
	}

	public String getResponsavelAprovacao() {
		return this.responsavelAprovacao;
	}

	public void setResponsavelAprovacao(String responsavelAprovacao) {
		this.responsavelAprovacao = responsavelAprovacao;
	}

	public BigDecimal getSaldo() {
		return this.saldo;
	}

	public void setSaldo(BigDecimal saldo) {
		this.saldo = saldo;
	}

	public int getTipoConta() {
		return this.tipoConta;
	}

	public void setTipoConta(int tipoConta) {
		this.tipoConta = tipoConta;
	}

	public Cliente getCliente() {
		return this.cliente;
	}

	public void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	public List<DataAniversario> getDataAniversarios() {
		if (dataAniversarios==null) {
			dataAniversarios = new ArrayList<DataAniversario>();
		}
		
		
		return this.dataAniversarios;
	}

	protected void setDataAniversarios(List<DataAniversario> dataAniversarios) {
		this.dataAniversarios = dataAniversarios;
	}

	public DataAniversario addDataAniversario(DataAniversario dataAniversario) {
		getDataAniversarios().add(dataAniversario);
		dataAniversario.setConta(this);

		return dataAniversario;
	}

	public DataAniversario removeDataAniversario(DataAniversario dataAniversario) {
		getDataAniversarios().remove(dataAniversario);
		dataAniversario.setConta(null);

		return dataAniversario;
	}

	public List<Movimento> getMovimentos() {
		return this.movimentos;
	}

	protected void setMovimentos(List<Movimento> movimentos) {
		this.movimentos = movimentos;
	}

	public Movimento addMovimento(Movimento movimento) {
		getMovimentos().add(movimento);
		movimento.setConta(this);

		return movimento;
	}

	private Movimento removeMovimento(Movimento movimento) {
		getMovimentos().remove(movimento);
		movimento.setConta(null);

		return movimento;
	}
	
	public static String getFindAll() {
		return "Conta.findAll";
	}
	
	public ContaDTO toDTO() {
		ContaDTO dto = new ContaDTO();
		
		/*Mapper mapper = new DozerBeanMapper();
        dto = mapper.map(this, ContaDTO.class);*/
				
		ClienteDTO cdto = cliente.toDTOLazy();
		dto.setCliente(cdto);
		dto.setCodigo(codigo);
		dto.setDtCriacao(dtCriacao);
		dto.setEstadoConta(estadoConta);
		dto.setFkAgencia(fkAgencia);
		dto.setLimite(limite);
		dto.setPkConta(pkConta);
		dto.setRespnsavelAbertura(respnsavelAbertura);
		dto.setResponsavelAprovacao(responsavelAprovacao);
		dto.setSaldo(saldo);
		dto.setTipoConta(tipoConta);
		
		Iterator<DataAniversario> iter = dataAniversarios.iterator();
		
		while(iter.hasNext()) {
			dto.addDataAniversario(iter.next().toDTO());
		}
		
		Iterator<Movimento> iter1 = movimentos.iterator();
		
		while(iter1.hasNext()) {
			dto.addMovimento(iter1.next().toDTO());
		}
        
        return dto;
	}
	
	public ContaDTO toDTOLazy() {
		ContaDTO dto = new ContaDTO();
		
		/*Mapper mapper = new DozerBeanMapper();
        dto = mapper.map(this, ContaDTO.class);*/
				
		ClienteDTO cdto = cliente.toDTOLazy();
		dto.setCliente(cdto);
		dto.setCodigo(codigo);
		dto.setDtCriacao(dtCriacao);
		dto.setEstadoConta(estadoConta);
		dto.setFkAgencia(fkAgencia);
		dto.setLimite(limite);
		dto.setPkConta(pkConta);
		dto.setRespnsavelAbertura(respnsavelAbertura);
		dto.setResponsavelAprovacao(responsavelAprovacao);
		dto.setSaldo(saldo);
		dto.setTipoConta(tipoConta);
		
		/*Iterator<DataAniversario> iter = dataAniversarios.iterator();
		
		while(iter.hasNext()) {
			dto.addDataAniversario(iter.next().toDTO());
		}
		
		Iterator<Movimento> iter1 = movimentos.iterator();
		
		while(iter1.hasNext()) {
			dto.addMovimento(iter1.next().toDTO());
		}*/
        
        return dto;
	}

	
	

	public void sacar(BigDecimal valor) throws BankException {

		
		double cobertura = (saldo.doubleValue()+limite.doubleValue())-valor.doubleValue();
		
		if (cobertura<0) {
			throw new BankException("Saldo insuficiente para completar a operacao");
		}
				
		saldo = saldo.subtract(valor);
		
	}
	
	public void depositar(BigDecimal valor) {
		
		
		saldo = saldo.add(valor);
		
				
	}
	
	public void AtualizarDataAniversarioSaque(BigDecimal valor) {
		 Calendar c = Calendar.getInstance();
		 Date d = new Date();
		 
		 BigDecimal resto = valor;
		 
		 Iterator<DataAniversario> i1 = dataAniversarios.iterator();
		 
		 while (i1.hasNext()) {
			if (resto.compareTo(BigDecimal.valueOf(0))==0) {
				break;
			}
			 DataAniversario ani = i1.next();
				if (ani.getValorData().compareTo(resto) >= 0) {
					ani.setValorData(ani.getValorData().subtract(resto));
					break;
				} else {
					ani.setValorData(BigDecimal.valueOf(0));
					resto = resto.subtract(ani.getValorData());
				}
				
			}
		 
	}
	

	public void AtualizarDataAniversarioDeposito(BigDecimal valor) {
		 Calendar c = Calendar.getInstance();
		 Date d = new Date();
		 
		 String dia = String.valueOf(c.get(Calendar.DAY_OF_MONTH));
		 String mes = String.valueOf(c.get(Calendar.MONTH)+1);
		 String token = dia+mes;
		 boolean achou = false;
		 
		 if (dataAniversarios.isEmpty()) {
		 
			 DataAniversario data = new DataAniversario();
			 data.setConta(this);
			 data.setDataAniversarioConta(token);
			 data.setValorData(valor);
			 addDataAniversario(data);
			 return;
		 } 		 
		 
		 Iterator<DataAniversario> i = dataAniversarios.iterator();
		 
		 while (i.hasNext()) {
			DataAniversario ani = i.next();
			if (ani.getDataAniversarioConta().equalsIgnoreCase(token)) {
				ani.setValorData(ani.getValorData().add(valor));
				achou=true;
				break;
			}
		 }
			 
		 if (!achou) {
			 DataAniversario data = new DataAniversario();
			 data.setConta(this);
			 data.setDataAniversarioConta(token);
			 data.setValorData(valor);
			 addDataAniversario(data);
		 }
		
		
		
	}

	
	public void alterarEstado(int novoestado) {
		estadoConta=novoestado;
	}

	@Override
	public String toString() {
		return "Conta [pkConta=" + pkConta + ", codigo=" + codigo
				+ ", dtCriacao=" + dtCriacao + ", estadoConta=" + estadoConta
				+ ", fkAgencia=" + fkAgencia + ", limite=" + limite
				+ ", respnsavelAbertura=" + respnsavelAbertura
				+ ", responsavelAprovacao=" + responsavelAprovacao + ", saldo="
				+ saldo + ", tipoConta=" + tipoConta + ", cliente=" + cliente
				+ ", dataAniversarios=" + dataAniversarios + ", movimentos="
				+ movimentos + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((codigo == null) ? 0 : codigo.hashCode());
		result = prime * result + fkAgencia;
		result = prime * result + pkConta;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Conta other = (Conta) obj;
		if (codigo == null) {
			if (other.codigo != null)
				return false;
		} else if (!codigo.equals(other.codigo))
			return false;
		if (fkAgencia != other.fkAgencia)
			return false;
		if (pkConta != other.pkConta)
			return false;
		return true;
	}
	
	
	
	
	
	

}